/*!
 * jQuery Pager Plugin v1.0.0
 * https://git.oschina.net/mihui/mPager.git
 *
 * Copyright (c) 2015 Mi Hui (http://mihui.net)
 * Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php).
 * 2015/05/22
 * 
 * SAMPLE CODE:
 * 
 * // construct pager, no HTML will be available yet
 * var mPager = $.mPager({});
 * //Test
 
 * //{} is the initialize option object to override the default settings:
 * // 	- pageCount: how many pages
 * // 	- currentPage: current page index
 * // 	- visiblePage: how many navigation links
 * // 	- labelFirst: first page label
 * // 	- labelLast: last page label
 * // 	- pageSize: how many items in a page
 * // 	- indexStart: start cursor
 * // 	- indexEnd: end cursor
 * 
 * //	- onChanged(deferred, data): after the page navigation is done
 * //	- onChanging(data): before navigating to anther page
 *  
 * //	- selector: jQuery selector of the pager container
 *  
 * // generate HTML when it's necessary, parameter is pageCount
 * mPager.generate(100);
 * 
 * // use event handler
 * // deferred.resolve(); must be called in the scope of this method if you're overriding it
 * // so consider to override this when you're having an AJAX call
 * mPager.onChanged(function(deferred, data){
 *     deferred.resolve();
 * });
 * 
 * // jQuery AJAX sample:
 * mPager.onChanged(function(deferred, data){
 *     $.ajax({
 *     	 // ......
 *       success: function(){
 *       	deferred.resolve({ });
 *       },
 *       error: function(){
 *       	deferred.reject({ });
 *       }
 *       // ......
 *     });
 * });
 * 
 * When you're having an AJAX call, you could leverage the APIs below to query specific range of records:
 * 
 * mPager.getIndexStart();
 * mPager.getIndexEnd();
 * mPager.getPageSize();
 * 
 * For instance (with event handler):
 * mPager.onChanged(function(deferred, data){
 * 	$.ajax({
 * 		url: 'your request url',
 *		data: {
 *	 		startRow: mPager.getIndexStart(),
			toRow: mPager.getIndexEnd()
 *		},
 *		success: function(data, textStatus, errorThrown){
 *       	deferred.resolve({ });
 *		},
 *		error: function(jqXHR, textStatus, errorThrown){
 *			deferred.reject({ });
 *		}
 *		// ......
 * 	});
 * });
 * 
 * //- deferred: should be used for asynchronous handling of data, events, etc...
 * //- data: pager related data
 */
;(function($){
	$.extend({
		mPager: function(options) {
			var settings = {
				pageCount: 0,			// how many pages
				currentPage: 1, 		// current page index
				visiblePage: 10, 		// how many navigation links
				
				labelFirst: 'First',	// first page label
				labelLast: 'Last',		// last page label
				
				pageSize: 10, 			// how many items in a page
				indexStart: 0, 			// start cursor
				indexEnd: 10, 			// end cursor
				/**
				 * after the process is done. e.g. ajax, event, etc...
				 * 
				 * @param deferred {Deferred}
				 * @param data {Object}
				 */
				onChanged: function(deferred, data){
					deferred.resolve({ data : data });
					return deferred;
				},
				/**
				 * before the process is being invoked
				 * 
				 * @param data {Object}
				 */
				onChanging: function(data){
					
				},
				selector: '.data-pager' // container selector of pager
			};
			$.extend(settings, options || {});
			/**
			 * process the pager with response data
			 * 
			 * @param startPage
			 * @param endPage
			 * @returns {String}
			 */
			var loop = function(startPage, endPage) {
				var content = '';
				for (var i = startPage; i < endPage; i++) {
					var pageNumber = (i + 1);
					if (pageNumber == settings.currentPage) {
						content += '<li class="current">';
					}
					else {
						content += '<li>';
					}
					content += '<a data-page="' + pageNumber + '">';
					content += (pageNumber < 10 ? ('0' + pageNumber) : pageNumber);
					content += '</a>';
					content += '</li>';
				}
				return content;
			},
			/**
			 * process HTML
			 * 
			 * @param pageCount
			 * @returns {String}
			 */
			process = function(pageCount) {
				var content = '';
				var halfway = Math.round(settings.visiblePage / 2);
				if (pageCount > 1) {
					content = '<ul class="pager">';
					if (pageCount < settings.visiblePage) {
						content += loop(0, pageCount);
					}
					else {
						if (settings.currentPage > 1) {
							content += '<li><a data-page="1">'+settings.labelFirst+'</a></li>';
						}
						if (settings.currentPage - halfway > 0) {
							if (settings.currentPage + halfway < pageCount) {
								content += loop(settings.currentPage - halfway, settings.currentPage + halfway);
							}
							else {
								content += loop((pageCount - settings.visiblePage), pageCount);
							}
						}
						else {
							content += loop(0, settings.visiblePage);
						}
						if (settings.currentPage < pageCount) {
							content += '<li><a data-page="' + (pageCount) + '">'+settings.labelLast+'</a></li>';
						}
					}
					content += '</ul>';
				}
				return content;
			},
			navigate = function(result){
				this.currentPage = result.currentPage;
				var d = $.Deferred();
				settings.onChanged(d, result);
				return d;
			};

			var jSelf = $(settings.selector);
			jSelf.on('click', 'li:not(.current) > a', function(evt){
				var p = $(this).attr('data-page');
				var currentPage = Number(p);
				var preparedData = {
					currentPage: currentPage,
					indexStart: (currentPage-1)*settings.pageSize,
					indexEnd: (currentPage)*settings.pageSize
				};
				settings.onChanging(preparedData);
				settings.currentPage = currentPage;
				settings.indexStart = (settings.currentPage-1)*settings.pageSize;
				settings.indexEnd = (settings.currentPage)*settings.pageSize;
				navigate(preparedData).then(function(data){
					var pagerHTML = process(settings.pageCount);
					jSelf.html(pagerHTML);
				}).fail(function(error){
					// TODO: should handle the error
				});
			});
			return {
				generate: function(pageCount, totalCount){
					settings.pageCount = pageCount;
					var pagerHTML = process(settings.pageCount);
					jSelf.each(function(k){
						var jContainer = $(this);
						jContainer.html(pagerHTML);
					})
				},
				getIndexStart: function(){
					return settings.indexStart;
				},
				getIndexEnd: function(){
					return settings.indexEnd;
				},
				getPageSize: function(){
					return settings.pageSize;
				},
				onChanged: function(callback){
					settings.onChanged = callback;
				}
			};
		}
	});
})(jQuery);

